import type {StorageEngine} from '@/types';

/**
 * 存储数据包装接口
 * 在业务数据基础上添加操作标识元数据
 */
interface StorageWrapper {
    // 原始业务负载，保持原样（对象/数组/字符串/数字等）
    __payload: any;
    // 操作来源标识：当前 tab ID
    __sourceTabId?: number | null;
    // 操作时间戳
    __timestamp?: number;
}

/**
 * Chrome Storage Local 实现存储引擎接口
 * 提供基于 Chrome Extension MV3 Storage API 的数据持久化
 * 支持类型安全的存储操作、错误处理机制和 tabId 标识
 */
export class ChromeStorageEngine implements StorageEngine {
    private currentTabId: number | null = null;
    private initPromise: Promise<void> | null = null;

    /**
     * 初始化当前 tabId
     * 在 Chrome 扩展环境中获取当前标签页 ID
     */
    private async init(): Promise<void> {
        if (this.initPromise) return this.initPromise;

        this.initPromise = (async () => {
            try {
                if (typeof chrome !== 'undefined' && chrome.tabs?.getCurrent) {
                    const tab = await chrome.tabs.getCurrent();
                    this.currentTabId = tab?.id || null;
                } else {
                    console.warn('Chrome tabs API 不可用，禁用自身操作识别');
                    this.currentTabId = null;
                }
            } catch (error) {
                console.warn('无法获取当前 tabId，禁用自身操作识别:', error);
                this.currentTabId = null;
            }
        })();

        return this.initPromise;
    }

    /**
     * 保存单个键值对到 Chrome Storage Local
     * 自动添加 tabId 和时间戳标识
     * @param key 存储键名
     * @param data 要保存的数据
     * @throws 存储失败时抛出错误
     */
    async save<T>(key: string, data: T): Promise<void> {
        // 确保 tabId 已初始化
        await this.init();

        // 包装数据：将业务数据放到 __payload，避免数组/字符串被错误展开
        const wrappedData: StorageWrapper = {
            __payload: data as any,
            __sourceTabId: this.currentTabId,
            __timestamp: Date.now(),
        };

        try {
            // 使用Chrome Storage Local API保存数据
            await chrome.storage.local.set({[key]: wrappedData});
        } catch (error) {
            console.error(`保存数据失败 [${key}]:`, error);
            throw error;
        }
    }

    /**
     * 从 Chrome Storage Local 加载单个键的数据
     * 自动清理元数据，只返回纯业务数据
     * @param key 存储键名
     * @returns 纯业务数据或 null
     * @throws 加载失败时返回null但会记录错误
     */
    async load<T>(key: string): Promise<T | null> {
        try {
            // 从Chrome Storage Local读取数据
            const result = await chrome.storage.local.get([key]);
            const rawData = result[key];
            if (!rawData || typeof rawData !== 'object') return null;
            const wrapper = rawData as Partial<StorageWrapper>;
            if (!('__payload' in wrapper)) return null;
            return wrapper.__payload as T;
        } catch (error) {
            console.error(`加载数据失败 [${key}]:`, error);
            return null;
        }
    }

    /**
     * 从 Chrome Storage Local 删除指定键的数据
     * @param key 要删除的存储键名
     * @throws 删除失败时抛出错误
     */
    async remove(key: string): Promise<void> {
        try {
            // 删除Chrome Storage中的指定键
            await chrome.storage.local.remove([key]);
        } catch (error) {
            console.error(`从存储删除${key}失败:`, error);
            throw error;
        }
    }

    /**
     * 清空所有 Chrome Storage Local 数据
     * @throws 清空失败时抛出错误
     */
    async clear(): Promise<void> {
        try {
            // 清空所有Chrome Storage数据
            await chrome.storage.local.clear();
        } catch (error) {
            console.error('清空存储失败:', error);
            throw error;
        }
    }

    /**
     * 批量保存多个键值对到 Chrome Storage Local
     * 自动为所有数据添加 tabId 和时间戳标识
     * @param items 要保存的键值对对象
     * @throws 保存失败时抛出错误
     */
    async saveBulk(items: Record<string, any>): Promise<void> {
        // 确保 tabId 已初始化
        await this.init();

        // 为所有数据项添加操作标识元数据（使用 __payload 包裹）
        const wrappedItems: Record<string, StorageWrapper> = {};
        for (const [key, data] of Object.entries(items)) {
            wrappedItems[key] = {
                __payload: data as any,
                __sourceTabId: this.currentTabId,
                __timestamp: Date.now(),
            };
        }

        try {
            // 批量保存包装后的数据
            await chrome.storage.local.set(wrappedItems);
        } catch (error) {
            console.error('批量保存到存储失败:', error);
            throw error;
        }
    }

    /**
     * 批量从 Chrome Storage Local 加载多个键的数据
     * 自动清理所有数据的元数据，只返回纯业务数据
     * @param keys 要加载的存储键名数组
     * @returns 包含所有请求键值对的纯业务数据对象
     * @throws 加载失败时返回空对象但会记录错误
     */
    async loadBulk(keys: string[]): Promise<Record<string, any>> {
        try {
            // 批量读取多个键的数据
            const rawResult = await chrome.storage.local.get(keys);
            const cleanResult: Record<string, any> = {};

            for (const [key, rawData] of Object.entries(rawResult)) {
                if (rawData && typeof rawData === 'object' && '__payload' in (rawData as any)) {
                    cleanResult[key] = (rawData as StorageWrapper).__payload;
                }
            }

            return cleanResult;
        } catch (error) {
            console.error('批量从存储加载失败:', error);
            return {};
        }
    }

    /**
     * 检查存储变化是否为当前 tab 的操作
     * 用于避免自身操作触发不必要的同步
     * @param changeData - 存储变化数据
     * @returns 是否为自身操作
     */
    isOwnOperation(changeData: any): boolean {
        // 如果没有操作标识或当前 tabId 未知，则认为不是自身操作
        if (!changeData || this.currentTabId === null) return false;

        // 检查操作来源是否为当前 tab
        return changeData.__sourceTabId === this.currentTabId;
    }

    /**
     * 获取所有存储数据（性能优化版本）
     * @returns 所有存储的键值对
     */
    async getAllData(): Promise<Record<string, any>> {
        try {
            const result = await chrome.storage.local.get(null);
            // 解包装所有数据，只返回业务负载
            const unwrapped: Record<string, any> = {};
            for (const [key, wrapped] of Object.entries(result)) {
                if (wrapped && typeof wrapped === 'object' && '__payload' in wrapped) {
                    unwrapped[key] = (wrapped as StorageWrapper).__payload;
                } else {
                    // 兼容未包装的旧数据
                    unwrapped[key] = wrapped;
                }
            }
            return unwrapped;
        } catch (error) {
            console.error('获取所有数据失败:', error);
            return {};
        }
    }

    /**
     * 批量删除多个键的数据
     * @param keys 要删除的键名数组
     */
    async deleteBulk(keys: string[]): Promise<void> {
        try {
            await chrome.storage.local.remove(keys);
        } catch (error) {
            console.error('批量删除失败:', error);
            throw error;
        }
    }
}

// 默认导出ChromeStorage实例（单例模式）
export const chromeStorage = new ChromeStorageEngine();
